/* 
 * File:   JServer.cpp
 * Author: johnneyshi
 * 
 * Created on 2013年1月26日, 下午1:10
 */

#include "JServer.h"
#include <sys/socket.h>
#include <sys/epoll.h>
#include <string.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <arpa/inet.h>
#include "JException.h"
#include "JLog.h"
#include <iostream>
#include <unistd.h>
#include <stdio.h>
#include "JException.h"
#include "JLog.h"
using namespace std;


JServer::JServer() 
{
}

JServer::JServer(std::string _ip, int _port) : ip(_ip),port(_port)
{
    
}

//JServer::JServer(const JServer& orig) 
//{
//    
//}

void JServer::Init(std::string _ip, int _port)
{
    this->ip = _ip;
    this->port = _port;
    epoll.Create(200);
}

JServer::~JServer() {
}

std::string JServer::GetIP()
{
    return this->ip;
}

int JServer::GetPort()
{
    return this->port;
}

void JServer::Start()
{
    int listenFd = Bind(this->ip,this->port);
    //std::cout << "bind success:" << listenFd << std::endl;
    Wait(listenFd);
    while(true)
    {
        sleep(30000);
    }
}

int JServer::Bind(std::string _ip,int _port)
{
    struct sockaddr_in serverAddr;
    bzero(&serverAddr,sizeof(sockaddr_in));
    
    int listenFd = socket(AF_INET,SOCK_STREAM,0);
    if(listenFd < -1)
    {
        throw JException("JServer::Bind listenFd error.");
    }
    SetNonBlock(listenFd);
    serverAddr.sin_family = AF_INET;
    inet_aton(_ip.c_str(),&serverAddr.sin_addr);
    serverAddr.sin_port = htons(_port);
    if(bind(listenFd,(struct sockaddr*)&serverAddr,sizeof(sockaddr_in)) < 0)
    {
        throw JException("ScheduleServer::Bind bind error.");
    }
    if(listen(listenFd,5) < 0)
    {
        throw JException("ScheduleServer::Bind listen error.");
    }
    return listenFd;
}

void JServer::SetNonBlock(int fd)
{
    if(fcntl(fd,F_SETFL,fcntl(fd,F_GETFL,0) | O_NONBLOCK) == -1)
    {
        
    }
}


void JServer::Wait(int fd)
{
    struct sockaddr_in clientAddr;
    bzero(&clientAddr,sizeof(sockaddr_in));
    socklen_t clientSocketLength = sizeof(sockaddr_in);
    
//    struct epoll_event ev;
//    struct epoll_event allEvent[200];

    JLog::Log(JLogMessage,"Listen fd:%d\n",fd);
    epoll.AddFd(fd,EPOLLIN);
//    if(epoll_ctl(epollHandler,EPOLL_CTL_ADD,fd,&ev) < 0)
//    {
//        throw JException("JServer::Wait epoll_ctl error.");
//    }
    while(true)
    {
        //cout << "hello" << endl;
        int maxCount = 200;
        int newFd;
        //int eventCount = epoll_wait(epollHandler,allEvent,maxCount,-1);
        std::vector<int> fds = epoll.Wait();
        JLog::Log(JLogMessage,"epoll_wait wait something.\n");
        for(int i = 0;i < fds.size(); ++i)
        {
            //New connection come.
            if(fds[i] == fd)
            {
                newFd = accept(fd,(struct sockaddr*)&clientAddr,&clientSocketLength);
                JLog::Log(JLogMessage,"Server:get new fd:%d\n",newFd);
                if(newFd < 0)
                {
                    throw JException("JServer::Wait accept error.");
                }
                else
                {
                    DealNewConnfd(newFd);
                }
            }
            else
            {
                
                DealEpollFd(fds[i]);
            }
        }
    }
}

void JServer::DealEpollFd(int fd)
{
    cout << "HandleMessage" << endl;
    char buff[1024];
    int n = 0;
    while(true)
    {
        bzero(buff,1024);
        //cout << "hello" << endl;
        n = read(fd,buff,1024);
        //cout << "world" << endl;
        if(n <= 0)
        {
            break;
        }
        cout << "Receive message:" << buff;
    }
}

//JBuffer* JServer::GetAvailableBuffer()
//{
//    for(int i = 0;i < this->pBuffers.size(); ++i)
//    {
//        if(this->pBuffers[i]->IsInUsed() == false)
//        {
//            this->pBuffers[i]->SetInUsed();
//            return this->pBuffers[i];
//        }
//    }
//    JBuffer* buff = new JBuffer;
//    this->pBuffers.push_back(buff);
//    return this->pBuffers[this->pBuffers.size() - 1];
//}

void JServer::DealNewConnfd(int newFd)
{
//     char buff[200];
//                    sprintf(buff,"new connection come: fd %d",newFd);
//                    SetNonBlock(newFd);
//                    ev.events = EPOLLIN | EPOLLET;
//                    ev.data.fd = newFd;
//                    if(epoll_ctl(epollHandler,EPOLL_CTL_ADD,newFd,&ev) < 0)
//                    {
//                        throw JException("JServer::Wait epoll_ctl error.");
//                    }
}

ssize_t JServer::WriteFd(int fd, void* ptr, size_t nbytes, int sendfd)
{
    struct msghdr msg;  
    struct iovec iov[1];  
    // 有些系统使用的是旧的msg_accrights域来传递描述符，Linux下是新的msg_control字段  
//#ifdef HAVE_MSGHDR_MSG_CONTROL  
    union{ // 前面说过，保证cmsghdr和msg_control的对齐  
        struct cmsghdr cm;  
        char control[CMSG_SPACE(sizeof(int))];  
    }control_un;  
    struct cmsghdr *cmptr;   
    // 设置辅助缓冲区和长度  
    msg.msg_control = control_un.control;   
    msg.msg_controllen = sizeof(control_un.control);  
    // 只需要一组附属数据就够了，直接通过CMSG_FIRSTHDR取得  
    cmptr = CMSG_FIRSTHDR(&msg);  
    // 设置必要的字段，数据和长度  
    cmptr->cmsg_len = CMSG_LEN(sizeof(int)); // fd类型是int，设置长度  
    cmptr->cmsg_level = SOL_SOCKET;   
    cmptr->cmsg_type = SCM_RIGHTS;  // 指明发送的是描述符  
    *((int*)CMSG_DATA(cmptr)) = sendfd; // 把fd写入辅助数据中  
//#else  
//    msg.msg_accrights = (caddr_t)&sendfd; // 这个旧的更方便啊  
//    msg.msg_accrightslen = sizeof(int);  
//#endif  
    // UDP才需要，无视  
    msg.msg_name = NULL;  
    msg.msg_namelen = 0;  
    // 别忘了设置数据缓冲区，实际上1个字节就够了  
    iov[0].iov_base = ptr;  
    iov[0].iov_len = nbytes;  
    msg.msg_iov = iov;  
    msg.msg_iovlen = 1;  
    return sendmsg(fd, &msg, 0);  
}


ssize_t JServer::ReadFd(int fd, void* ptr, size_t nbytes, int* recvfd)
{
     struct msghdr msg;  
    struct iovec iov[1];  
    int n;  
    int newfd;  
//#ifdef HAVE_MSGHDR_MSG_CONTROL  
    union{ // 对齐  
    struct cmsghdr cm;  
    char control[CMSG_SPACE(sizeof(int))];  
    }control_un;  
    struct cmsghdr *cmptr;  
    // 设置辅助数据缓冲区和长度  
    msg.msg_control = control_un.control;  
    msg.msg_controllen = sizeof(control_un.control);  
//#else  
//    msg.msg_accrights = (caddr_t) &newfd; // 这个简单  
//    msg.msg_accrightslen = sizeof(int);  
//#endif   
      
    // TCP无视  
    msg.msg_name = NULL;  
    msg.msg_namelen = 0;  
    // 设置数据缓冲区  
    iov[0].iov_base = ptr;  
    iov[0].iov_len = nbytes;  
    msg.msg_iov = iov;  
    msg.msg_iovlen = 1;  
    // 设置结束，准备接收  
    if((n = recvmsg(fd, &msg, 0)) <= 0)  
    {  
        return n;  
    }  
//#ifdef HAVE_MSGHDR_MSG_CONTROL  
    // 检查是否收到了辅助数据，以及长度，回忆上一节的CMSG宏  
    cmptr = CMSG_FIRSTHDR(&msg);  
    if((cmptr != NULL) && (cmptr->cmsg_len == CMSG_LEN(sizeof(int))))  
    {  
    // 还是必要的检查  
        if(cmptr->cmsg_level != SOL_SOCKET)  
        {  
            printf("control level != SOL_SOCKET/n");  
            exit(-1);  
        }  
        if(cmptr->cmsg_type != SCM_RIGHTS)  
        {  
            printf("control type != SCM_RIGHTS/n");  
            exit(-1);  
        }  
    // 好了，描述符在这  
        *recvfd = *((int*)CMSG_DATA(cmptr));  
    }  
    else  
    {  
        if(cmptr == NULL) printf("null cmptr, fd not passed./n");  
        else printf("message len[%d] if incorrect./n", cmptr->cmsg_len);  
        *recvfd = -1; // descriptor was not passed  
    }  
//#else  
//    if(msg.msg_accrightslen == sizeof(int)) *recvfd = newfd;   
//    else *recvfd = -1;  
//#endif  
    return n;  
}

